/* License Notice:
**
** This program is free software: you can redistribute it and/or modify
**    it under the terms of the GNU General Public License as published by
**    the Free Software Foundation, either version 3 of the License, or
**    (at your option) any later version.
** This program is distributed in the hope that it will be useful,
**   but WITHOUT ANY WARRANTY; without even the implied warranty of
**   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
**   GNU General Public License for more details.
** You should have received a copy of the GNU General Public License
**   along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

/**
 * @date 2024/12/10
 * @brief A collection of useful simplifications for OpenGl.
 *
 * @todo Collect other bits of the OpenGl api that may be centralized here.
 */
#ifndef _OPENGL_HPP_
#define _OPENGL_HPP_

/*---- Includes ----*/
#include <cstddef>
#include "glad/gl.h"

#include <SDL2/SDL_video.h>

#include "event_manager.hpp"


/*---- Typedefs ----*/
//typedef GLenum glTextureUnit;
/** @brief A more elegant name to keep track of Gl Vertex Buffer Objects. */
typedef GLuint VertexBuffObj_t;
/** @brief A more elegant name to keep track of Gl Vertex Array Objects. */
typedef GLuint VertexArrayObj_t;
/** @brief A more elegant name to keep track of Gl Element Buffer Objects. */
typedef GLuint ElementBuffObj_t;
/** @brief A more elegant name to keep track of Gl Frame Buffer Objects. */
typedef GLuint FrameBuffObj_t;


/*---- Macros ----*/
/** @brief Converts RGB color values to float that can be understood by OpenGl. */
#define RGB2Float(value) (value/255.f)


/*---- Class Declaration ----*/
/**
 * @brief A class to hold some global procedures/values regarding the OpenGl API.
 * @remark Thread safe singleton according to Game Programming Patterns, it could also have been implemented as a static class.
 */
class OpenGl
{
    private:
        SDL_Window *p_sdlWindow = nullptr;
        SDL_GLContext glMainContext = nullptr; //typedef from void *
        SDL_GLContext glThreadContext = nullptr; //typedef from void *

        /* Event handling */
        EventManager *p_ev_mgr_instance = nullptr;
        listenerID_t id_high_ev_listener = 0;


    protected:
        //hide constructor to make singleton safe
        OpenGl ();


    public:
        static OpenGl& instance ();
        ~OpenGl ();

        //delete copy and move constructors and assign operators to make singleton safe
        OpenGl (OpenGl const&) = delete;            //Copy construct
        OpenGl (OpenGl&&) = delete;                 //Move construct
        OpenGl& operator= (OpenGl const&) = delete; //Copy assign
        OpenGl& operator= (OpenGl &&) = delete;     //Move assign

        void init (SDL_Window *sdl_win);

        /** @brief Returns the Gl context to be used in the main thread. */
        SDL_GLContext getMainContext () const { return this->glMainContext; }
        /** @brief Returns the Gl context to be used in background/working threads. */
        SDL_GLContext getBackgroundContext () const { return this->glThreadContext; }

        GLsync lockBackgroundContext ();
        void unlockBackgroundContext (GLsync lock);

        static void highPriorityEvents_cb (OpenGl *obj_this, const EventManager::event_s &ev);
};//END OpenGl


/**
 * @brief Some OpenGl objects can be shared to avoid creating identical copies.
 */
class SharedGlObjs
{
    private:


    protected:
        VertexBuffObj_t VBO = 0; ///<The list of points to use.
        ElementBuffObj_t EBO = 0; ///<The order of the points to form triangles.


    public:
        SharedGlObjs (std::size_t vert_size, const GLfloat vertices[], std::size_t index_size, const GLuint indexes[]);
        ~SharedGlObjs ();

        /** @brief Returns the Vertex Buffer Object being shared. */
        VertexBuffObj_t getVBO () const { return this->VBO; }
        /** @brief Returns the Element Buffer Object. */
        ElementBuffObj_t getEBO () const { return this->EBO; }
};//END SharedGlObjs

#endif //_OPENGL_HPP_

